
/* Generated by Interface Builder */

#import "Protos.h"
#import "Proto.h"
#import "Main.h"
#import <appkit/Matrix.h>
#import <appkit/Cell.h>
#import <appkit/TextField.h>
#import <objc/List.h>
#import <appkit/Application.h>
#import <appkit/OpenPanel.h>
#import <sys/param.h>


@implementation Protos

+ new
{
	self = [super new];
	list = [List new];
	return self;
}

// 	--------------------------------------------------------
// Abstraction of the interface.

- (char *)typename
{
	return (char *)[typename stringValue];
}
- settypename:(char *)atypename
{
	[typename setStringValue:atypename];
	return self;
}

- (char *)pathname
{
	return (char *)[pathname stringValue];
}
- setpathname:(char *)apathname
{
	[pathname setStringValue:apathname];
	return self;
}

- (char *)editor
{
	return (char *)[editor stringValue];
}
- seteditor:(char *)aneditor
{
	[editor setStringValue:aneditor];
	return self;
}

- (int)defaultopen
{
	return [[defaultopen selectedCell] tag];
}
- setdefaultopen:(int)open
{
	[defaultopen selectCellWithTag:open];
	return self;
}


// Fill in the interface for proto.
// If proto is nil, then fill in blanks.
- showtypedetails:proto
{
	if (proto)
	{
		[self settypename:[proto typename]];
		[self setpathname:[proto pathname]];
		[self seteditor:[proto editor]];
		if (strcmp([self editor], "")==0)
			[openineditor setEnabled:NO];
		else
			[openineditor setEnabled:YES];
		[self setdefaultopen:[proto defaultopen]];
		[openinws setEnabled:YES];
	}
	else
	{
		[self settypename:""];
		[self setpathname:""];
		[self seteditor:""];
		[self setdefaultopen:OPEN_EDITOR];
		[openineditor setEnabled:NO];
		[openinws setEnabled:NO];
	}
	return self;
}


// Load interface and initialize.
- loadnib
{
	int i;
	[NXApp loadNibSection:"Protos.nib" owner:self];
	// Delete the dummy entries used to set up matrix in InterfaceBuilder
	for (i=0; i<3; i++)
		[typematrix removeRowAt:0 andFree:YES];
	
	// Fill in entries for prototypes.
	for (i=0; i<[list count]; i++)
	{
		[typematrix addRow];
		[typematrix setTitle:[[list objectAt:i] typename] at:i:0];
	}
	
	[typematrix sizeToCells];
	[typematrix selectCellAt:0:0];
	[typematrix display];
	[self showtype:self];
	return self;
}


// Create a proto from the entries in the interface.
- formproto
{
	id proto = [Proto new
		:[self typename]:[self pathname]:[self editor]:[self defaultopen]];
	return proto;
}


// 	--------------------------------------------------------

// 	--------------------------------------------------------
// Respond to the interface.

// Display the interface.
- showwindow:sender
{
	static nibloaded = 0;
	
	if (nibloaded==0)
	{
		[self loadnib];
		nibloaded++;
	}
	[window makeKeyAndOrderFront:self];
	return self;
}

- openineditor:sender
{
	char fullname[MAXPATHLEN];
	[main openineditor:[main fullprotoname:fullname:[self selectedpathname]]:[self selectededitor]];
	return self;
}

- openinworkspace:sender
{
	char fullname[MAXPATHLEN];
	[main openinws:[main fullprotoname:fullname:[self selectedpathname]]];
	return self;
}

- remove:sender
{
	[self removefromlist:[self selectedname]];
	return self;
}

- modify:sender
{
	id	proto = [self formproto];
	int	newcell = [self findposinlist:[proto typename]];
	int	pos = [self addtolist:proto];
	if (newcell<0)
	{
		[typematrix setTitle:[proto typename] at:pos:0];
		[typematrix sizeToCells];
		[typematrix display];
	}
	[typematrix selectCellAt:pos:0];
	[remove setEnabled:YES];
	[self showtype:self];
	return self;
}


// Called when user clicks on entry in type list.
- showtype:sender
{
	char	*name = [self selectedname];
	id	proto = [self protoatpos:[self findposinlist:name]];
	[self showtypedetails:proto];
	return self;
}

// 	--------------------------------------------------------
// The list of proto's. The list is ordered alphabetically.

// The list.
- protoslist
{
	return list;
}

// Return the proto whose typename is name.
- protoforname:(char *)name
{
	int pos;
	pos = [self findposinlist:name];
	return [self protoatpos:[self findposinlist:name]];
}

/*
Return the position in the list of the proto with typename name.
If no proto has that name, return the position at which a new entry with that name should go.
*/
- (int)findposinlist:(char *)name
{
	int	len = [list count];
	int i = 0;
	int	compare = -1;
	while (i<len && compare < 0)
	{
		compare = strcmp([[list objectAt:i] typename], name);
		if (compare<0) i++;
	}
	if (compare==0)
		return i;
	else
		return -i;
}


// The proto at position pos.
- protoatpos:(int)pos
{
	return [list objectAt:pos];
}

/*
If a proto with the name typename as proto is already in the list, replace that entry (destroying the old entry), otherwise add a new entry.
Return the position of the added/modified entry.

The interface is not updated: have to avoid the interface in this routine since the list is loaded and accessed on startup, and the interface is not loaded until it is required.
*/
- (int)addtolist:proto
{
	id	old;
	int pos = [self findposinlist:[proto typename]];
	if (pos<=0)
	{
		// New entry.
		pos = -pos;
		[list insertObject:proto at:pos];
		[typematrix insertRowAt:pos];
	}
	else
	{
		// Modify entry.
		old = [list replaceObjectAt:pos with:proto];
		[old free];
	}
	return pos;
}


// Remove the proto with typename name and update the interface.
- (int)removefromlist:(char *)name
{
	int pos = [self findposinlist:name];
	if (pos>=0)
	{
		[list removeObjectAt:pos];
		[typematrix removeRowAt:pos andFree:YES];
		[typematrix sizeToCells];
		
		// Select the entry that was previous to the deleted entry in the list.
		if (pos==[typematrix cellCount]) pos--;
		[typematrix selectCellAt:pos:0];
		[typematrix display];
	}
	if ([typematrix cellCount]==0) [remove setEnabled:NO];
	[self showtype:self];
	return pos;
}


// Load the list.
- readprotos:(FILE *)fp
{
	id	proto;
	int	pos;
	if (list) [list free];
	list = [List new];
	do
	{
		proto = [Proto read:fp];
		if (proto)
		{
			pos = [self addtolist:proto];
		}
	}
	while (proto);
	return self;
}


// Store the list.
- writeprotos:(FILE *)fp
{
	int i;
	int count = [list count];
	for (i=0; i<count; i++)
		[[list objectAt:i] write:fp];
	return self;
}

//	--------------------------------------------------------

// Properties of the proto whose name is currently selected in the type list.

// The proto itself.
- selected
{
	char *name = (char *)[[typematrix selectedCell] title];
	if (strcmp(name, "") == 0)
		return nil;
	else
		return [self protoatpos:[self findposinlist:name]];
}

- (char *)selectedname
{
	return (char *)[[typematrix selectedCell] title];
}
- (char *)selectededitor
{
	return [[self selected] editor];
}
- (char *)selectedpathname;
{
	return [[self selected] pathname];
}

@end
